/*
 * QuadCurve.java  0.4.0 / Oct 24, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.swing.graphics;

import java.util.NoSuchElementException;

/**
 * Quad Curve Shape.
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class QuadCurve implements Shape {

// Private Fields. -------------------------------------------------------------

  private final int x1;
  private final int y1;
  private final int ctrlx;
  private final int ctrly;
  private final int x2;
  private final int y2;
  private Rectangle bounds; // NOPMD
  private int hashCode; // NOPMD

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new QuadCurve object.
   */
  public QuadCurve() {
    x1 = 0;
    y1 = 0;
    ctrlx = 0;
    ctrly = 0;
    x2 = 0;
    y2 = 0;
  }

  /**
   * Constructs new QuadCurve object.
   *
   * @param x1 the x coordinate of the curve's start point
   * @param y1 the y coordinate of the curve's start point
   * @param ctrlx the x coordinate of the curve's control point
   * @param ctrly the y coordinate of the curve's control point
   * @param x2 the x coordinate of the curve's end point
   * @param y2 the y coordinate of the curve's end point
   */
  public QuadCurve(int x1, int y1, int ctrlx, int ctrly, int x2, int y2) {
    this.x1 = x1;
    this.y1 = y1;
    this.ctrlx = ctrlx;
    this.ctrly = ctrly;
    this.x2 = x2;
    this.y2 = y2;
  }

  /**
   * Constructs new CubicCurve object.
   *
   * @param p1 the curve's start point
   * @param ctrl the curve's control point
   * @param p2 the curve's end point
   */
  public QuadCurve(Point p1, Point ctrl, Point p2) {
    x1 = p1.getX();
    y1 = p1.getY();
    ctrlx = ctrl.getX();
    ctrly = ctrl.getY();
    x2 = p2.getX();
    y2 = p2.getY();
  }

// Public Methods. -------------------------------------------------------------

  /**
   * Returns the x coordinate of the curve's start point.
   *
   * @return the x coordinate of the curve's start point
   */
  public int getX1() {
    return x1;
  }

  /**
   * Returns the y coordinate of the curve's start point.
   *
   * @return the y coordinate of the curve's start point
   */
  public int getY1() {
    return y1;
  }

  /**
   * Returns the x coordinate of the curve's control point.
   *
   * @return the x coordinate of the curve's control point
   */
  public int getCtrlX() {
    return ctrlx;
  }

  /**
   * Returns the y coordinate of the curve's control point.
   *
   * @return the y coordinate of the curve's control point
   */
  public int getCtrlY() {
    return ctrly;
  }

  /**
   * Returns the x coordinate of the curve's end point.
   *
   * @return the x coordinate of the curve's end point
   */
  public int getX2() {
    return x2;
  }

  /**
   * Returns the y coordinate of the curve's end point.
   *
   * @return the y coordinate of the curve's end point
   */
  public int getY2() {
    return y2;
  }

// Shape Interface Implementation. ---------------------------------------------

  /**
   * {@inheritDoc}
   */
  public boolean contains(int x, int y) {
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public Rectangle getBounds() {
    if (bounds == null) {
      int minx = min3(x1, x2, ctrlx);
      int miny = min3(y1, y2, ctrly);
      int maxx = max3(x1, x2, ctrlx);
      int maxy = max3(y1, y2, ctrly);
      bounds = new Rectangle(minx, miny, maxx - minx, maxy - miny);
    }
    return bounds;
  }

  /**
   * {@inheritDoc}
   */
  public PathIterator getPathIterator() {
    return new QuadPathIterator(this);
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  public boolean equals(Object obj) {
    if (obj == this) {
      return true;
    }
    if ((obj != null) && (obj.getClass() == getClass())) {
      QuadCurve c = (QuadCurve)obj;
      return ((c.getX1() == getX1()) && (c.getY1() == getY1()) &&
              (c.getCtrlX() == getCtrlX()) &&
              (c.getCtrlY() == getCtrlY()) &&
              (c.getX2() == getX2()) && (c.getY2() == getY2()));
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  public int hashCode() {
    if (hashCode == 0) {
      int hashCode = 67;
      hashCode = 443 * hashCode + getX1();
      hashCode = 443 * hashCode + getY1();
      hashCode = 443 * hashCode + getCtrlX();
      hashCode = 443 * hashCode + getCtrlY();
      hashCode = 443 * hashCode + getX2();
      hashCode = 443 * hashCode + getY2();
      this.hashCode = hashCode;
    }
    return hashCode;
  }

  /**
   * {@inheritDoc}
   */
  public String toString() {
    return getClass().getName() + "[x1=" + getX1() + ",y1=" + getY1() +
           ",ctrlx=" + getCtrlX() + ",ctrly=" + getCtrlY() + ",x2=" + getX2() +
           ",y2=" + getY2() + "]";
  }

// Inner Classes. --------------------------------------------------------------

  /**
   * Quad Path Iterator.
   */
  protected static class QuadPathIterator implements PathIterator {

    private final QuadCurve quad;
    private int iteration;

    /**
     * Constructs new QuadPathIterator object.
     *
     * @param quad the quad curve
     */
    public QuadPathIterator(QuadCurve quad) {
      this.quad = quad;
    }

    /**
     * {@inheritDoc}
     */
    public int getWindingRule() {
      return WIND_NON_ZERO;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isDone() {
      return (iteration > 1);
    }

    /**
     * {@inheritDoc}
     */
    public void next() {
      iteration++;
    }

    /**
     * {@inheritDoc}
     */
    public int currentSegment(int[] coords) {
      switch (iteration) {
        case 0:
          coords[0] = quad.getX1();
          coords[1] = quad.getY1();
          return SEG_MOVETO;
        case 1:
          coords[0] = quad.getCtrlX();
          coords[1] = quad.getCtrlY();
          coords[2] = quad.getX2();
          coords[3] = quad.getY2();
          return SEG_QUADTO;
        default:
          throw new NoSuchElementException("Quad Path Iterator out of bounds");
      }
    }

  }

// Private Static Methods. -----------------------------------------------------

  private static int min3(int i1, int i2, int i3) {
    int min = i1;
    if (i2 < min) {
      min = i2;
    }
    if (i3 < min) {
      min = i3;
    }
    return min;
  }

  private static int max3(int i1, int i2, int i3) {
    int max = i1;
    if (i2 > max) {
      max = i2;
    }
    if (i3 > max) {
      max = i3;
    }
    return max;
  }

}
